#pragma once
#include <algorithm>
#include <chrono>
#include <cmath>
#include <ctime>
#include <opencv2/opencv.hpp>

/* #include "ArmorClassifier.h" */
#include "ArmorBase.h"
#include "ArmorClassifierBase.h"
#include "BarDetector.h"
namespace hitcrt {
class ArmorAssemblerBase {
   public:
    ArmorAssemblerBase() = default;
    virtual bool assemble(const std::vector<LightBar>& lights,
                          const cv::Mat& image, std::vector<Armor>& armors);
    virtual ~ArmorAssemblerBase() {};
    ArmorAssemblerBase(const float parallelDeltaTheta, const float twoLengthScale, const float xDistanceScale,
                   const float distanceLengthScaleMin, const float distanceLengthScaleMax,
                   const float cornerAngleMin, const float cornerAngleMax/* ,
                   const ArmorClassifierBasePtr classifier */){
        m_parallelDeltaTheta = parallelDeltaTheta;
        m_twoLengthScale = twoLengthScale;
        m_xDistanceScale = xDistanceScale;
        m_distanceLengthScaleMax = distanceLengthScaleMax;
        m_distanceLengthScaleMin = distanceLengthScaleMin;
        m_cornerAngleMin = cornerAngleMin;
        m_cornerAngleMax = cornerAngleMax;
    };

   protected:
    virtual void cleanVectors();  // 清空vector数据

    bool findArmors(const std::vector<LightBar>& bars,
                    std::vector<Armor>& armors);  // 匹配具体调用
    void sortBarIndexImpl(std::vector<std::pair<int, float>>& indexPairs);
    bool sortRuleImpl(const std::pair<int, float>& indexPair1,
                      const std::pair<int, float>& indexPair2);

    void sortParallelBars(std::vector<std::pair<int, float>> indexPairs);

    virtual std::vector<std::pair<int, float>> getParallelBarIndexs(
        const std::vector<LightBar>& bars, const int label) = 0;

    virtual void match(const std::vector<LightBar>&
                           bars) = 0;  // 灯条匹配，将匹配结果写入m_barPairs

    // 判断pair是否为装甲板,除了几何尺寸的判断还有分类的实现
    virtual bool checkArmor(std::tuple<LightBar, LightBar, Pattern>&
                                barPair);  // 判断候选灯条组合是否为装甲板
    virtual bool isParallel(
        LightBar lightBar1,
        LightBar lightBar2) = 0;  // 灯条平行判断，包括平行度、长度、角度

    bool hasArmors(
        std::vector<Armor>& armors);  // 判断是否有装甲板,如果存在pair则创建
    virtual void createArmors(
        std::vector<Armor>& armors) = 0;  // 根据Pair创建装甲板vector
    virtual void sizeClassification(std::vector<Armor>& armors) = 0;
    virtual void initClassifier() = 0;
    // 参数
    float m_parallelDeltaTheta;
    float m_twoLengthScale;
    float m_xDistanceScale;
    float m_distanceLengthScaleMax;
    float m_distanceLengthScaleMin;
    float m_cornerAngleMin;
    float m_cornerAngleMax;
    float m_sizedistanceLengthScale;  // 用来区分装甲板大小的宽高比界限
    std::vector<int> m_labels;
    std::vector<bool> m_searchFlags;  // 检查该灯条是否已经配对过
    std::vector<int> m_indexs;
    std::vector<std::tuple<LightBar, LightBar, Pattern>> m_barPairs;
    cv::Mat m_srcImg;          // 原始图像,用于进行分类
    cv::Mat m_perspectiveImg;  //
    std::shared_ptr<ArmorClassifierBase> m_classifier;
    // std::shared_ptr<ArmorClassifierBase> m_classifierPtr;  // 数字识别分类器
};
/// TODO 需要继承、override和补充声明 ///
class ArmorAssembler final : public ArmorAssemblerBase {
   public:
    ArmorAssembler(const float parallelDeltaTheta, const float twoLengthScale, const float xDistanceScale,
                   const float distanceLengthScaleMin, const float distanceLengthScaleMax,
                   const float cornerAngleMin, const float cornerAngleMax/* ,
                   const ArmorClassifierBasePtr classifier */):ArmorAssemblerBase(parallelDeltaTheta,twoLengthScale,xDistanceScale,
                   distanceLengthScaleMin, distanceLengthScaleMax,
                   cornerAngleMin, cornerAngleMax/* ,
                   const ArmorClassifierBasePtr classifier */){
        m_parallelDeltaTheta = parallelDeltaTheta;
        m_twoLengthScale = twoLengthScale;
        m_xDistanceScale = xDistanceScale;
        m_distanceLengthScaleMax = distanceLengthScaleMax;
        m_distanceLengthScaleMin = distanceLengthScaleMin;
        m_cornerAngleMin = cornerAngleMin;
        m_cornerAngleMax = cornerAngleMax;
        std::string MODEL_LOCATION =
            "../src/param/mobileNet--20240519_102802.xml";  // 按自身情况修改变量名和路径
        m_classifier = std::make_shared<hitcrt::ArmorClassifierBase>(
            hitcrt::ArmorClassifierBase::OneChannel,
            ArmorClassifierBase::CLS_CONF);
        m_classifier->init(MODEL_LOCATION, 0.9, 11,
                           hitcrt::ArmorClassifierBase::CPU);
    };
    bool isParallel(LightBar lightBar1, LightBar lightBar2);
    std::vector<std::pair<int, float>> getParallelBarIndexs(
        const std::vector<LightBar>& bars, const int label);
    bool sortRuleImpl(const std::pair<int, float>& indexPair1,
                      const std::pair<int, float>& indexPair2);

    std::tuple<LightBar, LightBar, Pattern> makeBarPairImpl(
        const LightBar& bar1, const LightBar& bar2);
    void match(const std::vector<LightBar>& bars);
    void sizeClassification(std::vector<Armor>& armors);
    Armor createOneArmorImpl(std::tuple<LightBar, LightBar, Pattern> barPair);
    void createArmors(std::vector<Armor>& armors);
    bool checkFourAngleImpl(const LightBar& lightBar1,
                            const LightBar& lightBar2,
                            const float cornerAngleMin,
                            const float cornerAngleMax);
    bool checkProductImpl(const LightBar& lightBar1, const LightBar& lightBar2,
                          const float deltaThetaThresh);
    bool checkLengthDiffImpl(const LightBar& lightBar1,
                             const LightBar& lightBar2,
                             const float twoLengthScale);
    std::pair<int, float> getIdPairImpl(const int id,
                                        const std::vector<LightBar>& bars);
    void initClassifier();
};
}  // namespace hitcrt
